#pragma once

#include "glare.math.Prerequisites.h"

namespace Glare {

	class IntersectionUtils
	{
	public:
		/** Checks whether a given point is inside a triangle, in a
		2-dimensional (Cartesian) space.
		@remarks
		The vertices of the triangle must be given in either
		trigonometrical (anticlockwise) or inverse trigonometrical
		(clockwise) order.
		@param p
		The point.
		@param a
		The triangle's first vertex.
		@param b
		The triangle's second vertex.
		@param c
		The triangle's third vertex.
		@return
		If the point resides in the triangle, <b>true</b> is
		returned.
		@par
		If the point is outside the triangle, <b>false</b> is
		returned.
		*/
		static bool pointInTri2D(const Vector2& p, const Vector2& a, 
			const Vector2& b, const Vector2& c);



		/** Checks whether a given 3D point is inside a triangle.
		@remarks
		The vertices of the triangle must be given in either
		trigonometrical (anticlockwise) or inverse trigonometrical
		(clockwise) order, and the point must be guaranteed to be in the
		same plane as the triangle
		@param p
		p The point.
		@param a
		The triangle's first vertex.
		@param b
		The triangle's second vertex.
		@param c
		The triangle's third vertex.
		@param normal
		The triangle plane's normal (passed in rather than calculated
		on demand since the caller may already have it)
		@return
		If the point resides in the triangle, <b>true</b> is
		returned.
		@par
		If the point is outside the triangle, <b>false</b> is
		returned.
		*/
		static bool pointInTri3D(const Vector3& p, const Vector3& a, 
			const Vector3& b, const Vector3& c, const Vector3& normal);




		/** Ray / plane intersection, returns boolean result and distance. */
		static std::pair<bool, Real> intersects(const Ray& ray, const Plane& plane);

		/** Ray / sphere intersection, returns boolean result and distance. */
		static std::pair<bool, Real> intersects(const Ray& ray, const Sphere& sphere, 
			bool discardInside = true);

		/** Ray / box intersection, returns boolean result and distance. */
		static std::pair<bool, Real> intersects(const Ray& ray, const AxisAlignedBox& box);

		/** Ray / box intersection, returns boolean result and two intersection distance.
		@param ray
		The ray.
		@param box
		The box.
		@param d1
		A real pointer to retrieve the near intersection distance
		from the ray origin, maybe <b>null</b> which means don't care
		about the near intersection distance.
		@param d2
		A real pointer to retrieve the far intersection distance
		from the ray origin, maybe <b>null</b> which means don't care
		about the far intersection distance.
		@return
		If the ray is intersects the box, <b>true</b> is returned, and
		the near intersection distance is return by <i>d1</i>, the
		far intersection distance is return by <i>d2</i>. Guarantee
		<b>0</b> <= <i>d1</i> <= <i>d2</i>.
		@par
		If the ray isn't intersects the box, <b>false</b> is returned, and
		<i>d1</i> and <i>d2</i> is unmodified.
		*/
		static bool intersects(const Ray& ray, const AxisAlignedBox& box,
			Real* d1, Real* d2);

		/** Ray / triangle intersection, returns boolean result and distance.
		@param ray
		The ray.
		@param a
		The triangle's first vertex.
		@param b
		The triangle's second vertex.
		@param c
		The triangle's third vertex.
		@param normal
		The triangle plane's normal (passed in rather than calculated
		on demand since the caller may already have it), doesn't need
		normalised since we don't care.
		@param positiveSide
		Intersect with "positive side" of the triangle
		@param negativeSide
		Intersect with "negative side" of the triangle
		@return
		If the ray is intersects the triangle, a pair of <b>true</b> and the
		distance between intersection point and ray origin returned.
		@par
		If the ray isn't intersects the triangle, a pair of <b>false</b> and
		<b>0</b> returned.
		*/
		static std::pair<bool, Real> intersects(const Ray& ray, const Vector3& a,
			const Vector3& b, const Vector3& c, const Vector3& normal,
			bool positiveSide = true, bool negativeSide = true);

		/** Ray / triangle intersection, returns boolean result and distance.
		@param ray
		The ray.
		@param a
		The triangle's first vertex.
		@param b
		The triangle's second vertex.
		@param c
		The triangle's third vertex.
		@param positiveSide
		Intersect with "positive side" of the triangle
		@param negativeSide
		Intersect with "negative side" of the triangle
		@return
		If the ray is intersects the triangle, a pair of <b>true</b> and the
		distance between intersection point and ray origin returned.
		@par
		If the ray isn't intersects the triangle, a pair of <b>false</b> and
		<b>0</b> returned.
		*/
		static std::pair<bool, Real> intersects(const Ray& ray, const Vector3& a,
			const Vector3& b, const Vector3& c,
			bool positiveSide = true, bool negativeSide = true);

		/** Sphere / box intersection test. */
		static bool intersects(const Sphere& sphere, const AxisAlignedBox& box);

		/** Plane / box intersection test. */
		static bool intersects(const Plane& plane, const AxisAlignedBox& box);

		/** Ray / convex plane list intersection test. 
		@param ray The ray to test with
		@param planeList List of planes which form a convex volume
		@param normalIsOutside Does the normal point outside the volume
		*/
		static std::pair<bool, Real> intersects(
			const Ray& ray, const std::vector<Plane>& planeList, 
			bool normalIsOutside);
		/** Ray / convex plane list intersection test. 
		@param ray The ray to test with
		@param planeList List of planes which form a convex volume
		@param normalIsOutside Does the normal point outside the volume
		*/
		static std::pair<bool, Real> intersects(
			const Ray& ray, const std::list<Plane>& planeList, 
			bool normalIsOutside);

		/** Sphere / plane intersection test. 
		@remarks NB just do a plane.getDistance(sphere.getCenter()) for more detail!
		*/
		static bool intersects(const Sphere& sphere, const Plane& plane);

	};

}
